import path from "path";
import fs from "fs-extra";
import lib_string from "../@libs/lib_string";
import * as glob from "glob";
import { argv } from "process";

interface message_header_config {
	/** 消息头列表(例: int32 _sequence) */
	header_ss: string[];
	/** 消息名匹配正则 */
	match_reg_s: string;
}

interface message_id_config {
	/** id 键 */
	key_s: string;
	/** 消息名匹配正则 */
	match_reg_s: string;
}

/** 消息头 */
let message_header: message_header_config = {
	header_ss: ["int32 __sequence"],
	match_reg_s: "([^{]+?_c)",
};

/** 消息 id */
let message_id: message_id_config = {
	key_s: "int64 __id",
	match_reg_s: "([^{]+?_c)",
};

/** 项目根路径 */
let project_path_s = path.join(__dirname, "../../");
/** 消息 id 缓存路径 */
let id_cache_path_s: string;

if (argv.length > 3) {
	id_cache_path_s =
		argv[2][0] !== "." ? argv[2] : path.join(project_path_s, argv[2]);

	/** 协议文件路径列表 */
	const proto_path_ss: string[] = glob
		.globSync(
			argv
				.slice(3)
				.map((v_s) =>
					(v_s[0] !== "." ? v_s : path.join(project_path_s, v_s)).replace(
						/\\/g,
						"/"
					)
				)
		)
		.map((v2_s) => path.normalize(v2_s));

	if (proto_path_ss.length) {
		generate_message_header(proto_path_ss, message_header);
		generate_message_id(proto_path_ss, message_id);
	}
}

/** 获得消息号 */
function get_message_id(message_name_s_: string, cache_: any): void {
	if (cache_[message_name_s_]) {
		return cache_[message_name_s_];
	}

	let max_id_n = cache_["max_id_n"] ?? (cache_["max_id_n"] = 0);

	cache_[message_name_s_] = max_id_n + 1;
	cache_["max_id_n"] = max_id_n + 1;

	return max_id_n + 1;
}

/**
 * 生成消息头
 * @param proto_path_ss_ proto 文件路径
 * @param match_reg_s_ 匹配正则
 * @param head_ss_ 消息头列表
 */
function generate_message_header(
	proto_path_ss_: string[],
	config_: message_header_config
): void {
	const match_reg = new RegExp(`message ${config_.match_reg_s} {`);

	proto_path_ss_.forEach((v_s) => {
		let file_s = fs.readFileSync(v_s, "utf-8");
		/** 当前下标 */
		let read_index_n = 0;
		/** 迭代器 */
		let iterator: RegExpMatchArray | null;

		while ((iterator = file_s.slice(read_index_n).match(match_reg))) {
			/** 消息体内容 */
			const content_s = lib_string.get_block(
				file_s.slice(read_index_n + iterator.index!),
				{}
			)[0];

			/** 新消息体 */
			let new_content_s = content_s;
			/** 消息号插入位置 */
			let insert_index_n!: number;
			// 查找消息序号
			const match_result = content_s.match(/([^]*)(=[ ]*[\d]+;)/);

			// 不存在消息序号
			if (!match_result) {
				insert_index_n = file_s.indexOf("{", iterator.index) + 1;
			} else {
				/** 末尾序号 */
				const end_id_n = Number(
					match_result[2].match(/(?<==[ ]*)([\d]+)(?=[ ]*;)/g)![0]
				);

				/** 插入位置 */
				insert_index_n = match_result.index! + match_result[0].length;

				// 增加消息序号
				{
					for (let k3_n = end_id_n; k3_n > 0; k3_n--) {
						const match_result = new_content_s.matchAll(
							new RegExp(`(=| )${k3_n}(?=[ ]*;)`, "g")
						)!;

						/** 末尾的 id 位置 */
						let index_n!: number;

						for (const v4 of match_result) {
							insert_index_n = index_n = v4.index! + 1;
						}

						// 更新块内容
						new_content_s =
							new_content_s.slice(0, index_n) +
							String(k3_n + config_.header_ss.length) +
							new_content_s.slice(index_n + String(k3_n).length);
					}
				}

				// 更新插入位置
				insert_index_n = new_content_s.lastIndexOf("\n", insert_index_n) + 1;
			}

			// 添加消息头
			new_content_s =
				new_content_s.slice(0, insert_index_n) +
				`\n${config_.header_ss
					.map((v4_s, k4_n) => `${v4_s} = ${k4_n + 1};`)
					.join("\n")}\n` +
				new_content_s.slice(insert_index_n);

			// 更新文件内容
			{
				const block_start_index_n =
					file_s.indexOf("{", read_index_n + iterator.index!) + 1;

				file_s =
					file_s.slice(0, block_start_index_n) +
					new_content_s +
					file_s.slice(block_start_index_n + content_s.length);

				read_index_n = block_start_index_n + new_content_s.length + 1;
			}
		}

		fs.writeFileSync(v_s, file_s);
	});
}

/**
 * 生成消息 id
 * @param proto_path_ss_ proto 文件路径
 * @param match_reg_s_ 匹配正则
 * @param head_ss_ 消息头列表
 */
function generate_message_id(
	proto_path_ss_: string[],
	config_: message_id_config
): void {
	const message_id_cache_path_s = path.join(
		id_cache_path_s,
		"message_id_cache.json"
	);
	const message_id_cache = !fs.existsSync(message_id_cache_path_s)
		? {}
		: JSON.parse(fs.readFileSync(message_id_cache_path_s, "utf-8"));
	const match_reg = new RegExp(`message ${config_.match_reg_s} {`);

	proto_path_ss_.forEach((v_s) => {
		let file_s = fs.readFileSync(v_s, "utf-8");
		/** 当前下标 */
		let read_index_n = 0;
		/** 迭代器 */
		let iterator: RegExpMatchArray | null;

		while ((iterator = file_s.slice(read_index_n).match(match_reg))) {
			const name_s = iterator[1];
			/** 消息体内容 */
			const content_s = lib_string.get_block(
				file_s.slice(read_index_n + iterator.index!),
				{}
			)[0];

			/** 新消息体 */
			let new_content_s = content_s;
			/** 消息号插入位置 */
			let insert_index_n!: number;
			// 查找消息序号
			const match_result = content_s.match(/([^]*)(=[ ]*[\d]+;)/);

			// 不存在消息序号
			if (!match_result) {
				insert_index_n = file_s.indexOf("{", iterator.index) + 1;
			} else {
				/** 末尾序号 */
				const end_id_n = Number(
					match_result[2].match(/(?<==[ ]*)([\d]+)(?=[ ]*;)/g)![0]
				);

				/** 插入位置 */
				insert_index_n = match_result.index! + match_result[0].length;

				// 增加消息序号
				{
					for (let k3_n = end_id_n; k3_n > 0; k3_n--) {
						const match_result = new_content_s.matchAll(
							new RegExp(`(=| )${k3_n}(?=[ ]*;)`, "g")
						)!;

						/** 末尾的 id 位置 */
						let index_n!: number;

						for (const v4 of match_result) {
							insert_index_n = index_n = v4.index! + 1;
						}

						// 更新块内容
						new_content_s =
							new_content_s.slice(0, index_n) +
							String(k3_n + 1) +
							new_content_s.slice(index_n + String(k3_n).length);
					}
				}

				// 更新插入位置
				insert_index_n = new_content_s.lastIndexOf("\n", insert_index_n) + 1;
			}

			// 添加消息头
			new_content_s =
				new_content_s.slice(0, insert_index_n) +
				`\n${config_.key_s} = 1 [default=${get_message_id(
					name_s,
					message_id_cache
				)}];\n` +
				new_content_s.slice(insert_index_n);

			// 更新文件内容
			{
				const block_start_index_n =
					file_s.indexOf("{", read_index_n + iterator.index!) + 1;

				file_s =
					file_s.slice(0, block_start_index_n) +
					new_content_s +
					file_s.slice(block_start_index_n + content_s.length);

				read_index_n = block_start_index_n + new_content_s.length + 1;
			}
		}

		// 写入协议
		fs.writeFileSync(v_s, file_s);

		// 写入缓存
		fs.ensureDirSync(path.dirname(message_id_cache_path_s));
		fs.writeFileSync(message_id_cache_path_s, JSON.stringify(message_id_cache));
	});
}
